﻿using LxBasic;
using LxCore;
using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace LxCore
{
    public class BoundCond : MeshWithSelector, IIdentity
    {
        public BoundCond(FvBound bound)
        {
            Bound = bound;
        }
        public FvBound Bound;
        public ZoneCond InZoneCond => ResHelper.GetCond(Bound.InZone);
        protected FvJoint InJoint => Bound.InJoint;
        public JointCond InJointCond
        {
            get => InJoint == null ? null : ResHelper.GetCond(InJoint);
            set { RaisePropertyChanged(nameof(InJointCond)); }
        }
        public string Name
        {
            get => Bound.Name;
            set
            {
                Bound.Name = value;
                RaisePropertyChanged(nameof(Name));
            }
        }
        public int ID
        {
            get => Bound.ID;
            set
            {
                Bound.ID = value;
                RaisePropertyChanged(nameof(ID));
            }
        }


        #region 物理模型设置
        public bool IsCouplingEnabled
        {
            get
            {
                return InJoint == null ? false : ResHelper.GetCond(InJoint).IsEnabled;
            }
            set
            {
                if (InJoint == null) return;
                ResHelper.GetCond(InJoint).IsEnabled = value;
                RaisePropertyChanged(nameof(IsCouplingEnabled));
                CheckSetBound();
            }
        }

        public BoundTypes[] AvaliableBoundTypes
        {
            get => _AvaliableBountTypes;
            set
            {
                _AvaliableBountTypes = value;
                RaisePropertyChanged(nameof(AvaliableBoundTypes));
            }
        }
        private BoundTypes[] _AvaliableBountTypes;
        public BoundTypes BoundType
        {
            get => _BoundType;
            set
            {
                _BoundType = value;
                RaisePropertyChanged(nameof(BoundType));
            }
        }
        private BoundTypes _BoundType;

        public void CheckSetBound()
        {
            if (IsCouplingEnabled)
            {
                InJointCond.CheckSetJoint();
            }
            else
            {
                var zoneSet = InZoneCond;
                if (zoneSet.PhysicalModel == null)
                {
                    AvaliableBoundTypes = null;
                }
                else
                {
                    switch (zoneSet.PhysicalModel.PhysicalType)
                    {
                        case PhysicalTypes.固体: AvaliableBoundTypes = LxSim.Sim.Conditions.SolidBoundTypes; break;
                        case PhysicalTypes.流体: AvaliableBoundTypes = LxSim.Sim.Conditions.FluidBoundTypes; break;
                        default: throw new Exception("无可用边界条件");
                    }
                    if (!AvaliableBoundTypes.Contains(BoundType))
                    {
                        BoundType = AvaliableBoundTypes[0];
                    }
                }
            }
        }
        public WallThermalTypes WallThermalType
        {
            get => _WallThermalType;
            set { _WallThermalType = value; RaisePropertyChanged(nameof(WallThermalType)); }
        }
        private WallThermalTypes _WallThermalType = WallThermalTypes.定热流密度;
        public FieldBase<double> Temperature
        {
            get => _Temperature;
            set { _Temperature = value; RaisePropertyChanged(nameof(Temperature)); }
        }
        private FieldBase<double> _Temperature = new ConstField.Double(300);
        public FieldBase<double> HeatFlux_b
        {
            get => _HeatFlux_b;
            set { _HeatFlux_b = value; RaisePropertyChanged(nameof(HeatFlux_b)); }
        }
        private FieldBase<double> _HeatFlux_b = new ConstField.Double(0);
        public FieldBase<double> HeatFlux_a
        {
            get => _HeatFlux_a;
            set { _HeatFlux_a = value; RaisePropertyChanged(nameof(HeatFlux_a)); }
        }
        private FieldBase<double> _HeatFlux_a = new ConstField.Double(0);
        public FieldBase<double> Coupledh
        {
            get => _Coupledh;
            set { _Coupledh = value; RaisePropertyChanged(nameof(Coupledh)); }
        }
        private FieldBase<double> _Coupledh = new ConstField.Double(10);
        public FieldBase<double> CoupledT
        {
            get => _CoupledT;
            set { _CoupledT = value; RaisePropertyChanged(nameof(CoupledT)); }
        }
        private FieldBase<double> _CoupledT = new ConstField.Double(300);
        public bool IsNoSlipingWall
        {
            get => _IsNoSlipingWall;
            set { _IsNoSlipingWall = value; RaisePropertyChanged(nameof(IsNoSlipingWall)); }
        }
        private bool _IsNoSlipingWall = true;
        public bool IsStaticWall
        {
            get => _IsStaticWall;
            set { _IsStaticWall = value; RaisePropertyChanged(nameof(IsStaticWall)); }
        }
        private bool _IsStaticWall = true;
        public FieldBase<Vector3d> Velocity
        {
            get => _Velocity;
            set { _Velocity = value; RaisePropertyChanged(nameof(Velocity)); }
        }
        private FieldBase<Vector3d> _Velocity = new ConstField.Vector(new Vector3d());
        public bool IsNormalToBound
        {
            get => _IsNormalToBound;
            set { _IsNormalToBound = value; RaisePropertyChanged(nameof(IsNormalToBound)); }
        }
        private bool _IsNormalToBound = true;
        public FieldBase<double> VelocityMagnitude
        {
            get => _VelocityMagnitude;
            set { _VelocityMagnitude = value; RaisePropertyChanged(nameof(VelocityMagnitude)); }
        }
        private FieldBase<double> _VelocityMagnitude = new ConstField.Double(0);
        public FieldBase<double> Pressure
        {
            get => _Pressure;
            set { _Pressure = value; RaisePropertyChanged(nameof(Pressure)); }
        }
        private FieldBase<double> _Pressure = new ConstField.Double(0);
        //湍流相关
        public FieldBase<double> TurbIntensity
        {
            get => _TurbIntensity;
            set { _TurbIntensity = value; RaisePropertyChanged(nameof(TurbIntensity)); }
        }
        private FieldBase<double> _TurbIntensity = new ConstField.Double(0.01);
        public FieldBase<double> TurbVisRate
        {
            get => _TurbVisRate;
            set { _TurbVisRate = value; RaisePropertyChanged(nameof(TurbVisRate)); }
        }
        private FieldBase<double> _TurbVisRate = new ConstField.Double(10);
        //辐射相关
        public FieldBase<double> Emissivity
        {
            get => _Emissivity;
            set { _Emissivity = value; RaisePropertyChanged(nameof(Emissivity)); }
        }
        private FieldBase<double> _Emissivity = new ConstField.Double(0.8);//发射率epsilon，=吸收率alpha
        public FieldBase<double> Reflectivity
        {
            get => _Reflectivity;
            set { _Reflectivity = value; RaisePropertyChanged(nameof(Reflectivity)); }
        }
        private FieldBase<double> _Reflectivity = new ConstField.Double(0.2);//反射率rho，建议设置自动计算
        public FieldBase<double> Transmissivity
        {
            get => _Transmissivity;
            set { _Transmissivity = value; RaisePropertyChanged(nameof(Transmissivity)); }
        }
        private FieldBase<double> _Transmissivity = new ConstField.Double(0);//透射率gamma
        public bool IsReflectivityAutoCal
        {
            get => _IsReflectivityAutoCal;
            set { _IsReflectivityAutoCal = value; RaisePropertyChanged(nameof(IsReflectivityAutoCal)); }
        }
        private bool _IsReflectivityAutoCal = true;
        #endregion

        public override void FromJsonKV(string key, IJsonReader jsReader)
        {
            switch (key)
            {
                case nameof(Name): Name = jsReader.ReadString(); break;
                case nameof(IsCouplingEnabled): IsCouplingEnabled = jsReader.ReadBool(); break;
                case nameof(BoundType): BoundType = jsReader.ReadEnum<BoundTypes>(); break;
                case nameof(WallThermalType): WallThermalType = jsReader.ReadEnum<WallThermalTypes>(); break;
                case nameof(IsNoSlipingWall): IsNoSlipingWall = jsReader.ReadBool(); break;
                case nameof(IsStaticWall): IsStaticWall = jsReader.ReadBool(); break;
                case nameof(Temperature): jsReader.ReadObject(Temperature, e => Temperature = e); break;
                case nameof(HeatFlux_a): jsReader.ReadObject(HeatFlux_a, e => HeatFlux_a = e); break;
                case nameof(HeatFlux_b): jsReader.ReadObject(HeatFlux_b, e => HeatFlux_b = e); break;
                case nameof(Coupledh): jsReader.ReadObject(Coupledh, e => Coupledh = e); break;
                case nameof(CoupledT): jsReader.ReadObject(CoupledT, e => CoupledT = e); break;
                case nameof(Velocity): jsReader.ReadObject(Velocity, e => Velocity = e); break;
                case nameof(VelocityMagnitude): jsReader.ReadObject(VelocityMagnitude, e => VelocityMagnitude = e); break;
                case nameof(Pressure): jsReader.ReadObject(Pressure, e => Pressure = e); break;
                case nameof(IsNormalToBound): jsReader.ReadBool(); break;
                default: base.FromJsonKV(key, jsReader); break;
            }
        }
        public override void ToJsonKV(IJsonWriter jsWriter)
        {
            base.ToJsonKV(jsWriter);
            var inPhysical = InZoneCond.PhysicalModel;
            if (inPhysical == null) return;
            if (InJoint != null)
            {
                jsWriter.WriteBool(nameof(IsCouplingEnabled), IsCouplingEnabled);
            }
            if (IsCouplingEnabled)
            {
            }
            else
            {
                if (inPhysical.PhysicalType == PhysicalTypes.流体)
                {
                    jsWriter.WriteEnum(nameof(BoundType), BoundType);
                    switch (BoundType)
                    {
                        case BoundTypes.壁面:
                            jsWriter.WriteBool(nameof(IsNoSlipingWall), IsNoSlipingWall);
                            jsWriter.WriteBool(nameof(IsStaticWall), IsStaticWall);
                            if (IsNoSlipingWall && !IsStaticWall)
                            {
                                jsWriter.WriteObject(nameof(Velocity), Velocity, true);
                            }
                            break;
                        case BoundTypes.速度入口:
                            writeVel();
                            break;
                        case BoundTypes.压力出口:
                            jsWriter.WriteObject(nameof(Pressure), Pressure, true);
                            writeVel();
                            break;
                            void writeVel()
                            {
                                if (IsNormalToBound)
                                {
                                    jsWriter.WriteObject(nameof(VelocityMagnitude), VelocityMagnitude, true);
                                }
                                else
                                {
                                    jsWriter.WriteObject(nameof(Velocity), Velocity, true);
                                }
                            }
                    }

                }
                if (inPhysical.IsEnergyEnabled)
                {
                    jsWriter.WriteEnum(nameof(WallThermalType), WallThermalType);
                    switch (inPhysical.PhysicalType, BoundType, WallThermalType)
                    {
                        case (PhysicalTypes.固体, _, WallThermalTypes.定壁温):
                        case (PhysicalTypes.流体, BoundTypes.壁面, WallThermalTypes.定壁温):
                        case (PhysicalTypes.流体, BoundTypes.速度入口, _):
                        case (PhysicalTypes.流体, BoundTypes.压力出口, _):
                            jsWriter.WriteObject(nameof(Temperature), Temperature, true);
                            break;
                        case (PhysicalTypes.固体, _, WallThermalTypes.定热流密度):
                        case (PhysicalTypes.流体, BoundTypes.壁面, WallThermalTypes.定热流密度):
                            jsWriter.WriteObject(nameof(HeatFlux_a), HeatFlux_a, true);
                            jsWriter.WriteObject(nameof(HeatFlux_b), HeatFlux_b, true);
                            break;
                        case (PhysicalTypes.固体, _, WallThermalTypes.定换热系数):
                        case (PhysicalTypes.流体, BoundTypes.壁面, WallThermalTypes.定换热系数):
                            jsWriter.WriteObject(nameof(Coupledh), Coupledh, true);
                            jsWriter.WriteObject(nameof(CoupledT), CoupledT, true);
                            break;
                    }
                }

            }

        }
    }
}